#version 450 core

layout(std430, binding = 0) readonly buffer Octree { uint data[]; } octree;

#include "octree.glsl"

layout(binding = 1) uniform CameraUbo {
    vec4 position;
	vec4 look;
	vec4 right;
	vec4 up;
} cameraUbo;

layout(push_constant) uniform PushConstants {
	uint width;
	uint height;
	uint beamSize;
	float originSize;
} pushConstants;

layout(location = 0) out float outColor;


vec3 CameraGenRay(vec2 coord) {
	coord = coord * 2.0f - 1.0f;
	return normalize(cameraUbo.look.xyz - cameraUbo.right.xyz * coord.x - cameraUbo.up.xyz * coord.y);
}

vec3 GenCoarseRay() { return CameraGenRay(ivec2(gl_FragCoord.xy) / vec2(pushConstants.width, pushConstants.height) * pushConstants.beamSize); }
vec3 GenCoarseRay(in vec2 bias) {
	return CameraGenRay((vec2(ivec2(gl_FragCoord.xy)) + bias) / vec2(pushConstants.width, pushConstants.height) * pushConstants.beamSize);
}

float RayTangent(in vec3 x, in vec3 y) {
	float c = dot(x, y);
	return sqrt(1.0 - c * c) / abs(c);
}

void main() {
	vec3 o = cameraUbo.position.xyz;
	vec3 d = GenCoarseRay();
	float t0 = RayTangent(d, GenCoarseRay(vec2(0.5, 0.5)));
	float t1 = RayTangent(d, GenCoarseRay(vec2(-0.5, 0.5)));
	float t2 = RayTangent(d, GenCoarseRay(vec2(0.5, -0.5)));
	float t3 = RayTangent(d, GenCoarseRay(vec2(-0.5, -0.5)));
	float dirSZ = 2.0 * max(max(t0, t1), max(t2, t3)), t, size;
	outColor = OctreeRayMarchCoarse(o, d, pushConstants.originSize, dirSZ, t, size) ? max(0.0, t - size) : 1e10;
}
